﻿using Base.FileRemoteModel.UserFile.Model;
using Basic.FlowApplication.Interface;
using Basic.FlowApplication.Model;
using Basic.FlowApplication.Model.AuditItem;
using Basic.FlowApplication.Model.AuditLog;
using Basic.FlowCollect;
using Basic.FlowExtendService;
using Basic.FlowModel;
using Basic.FlowModel.AuditState;
using Basic.FlowRemoteModel;
using Basic.FlowRemoteModel.Application.Model;
using Basic.HrRemoteModel.Emp.Model;
using WeDonekRpc.Helper;

namespace Basic.FlowApplication.Extend
{
    internal class AuditLogListService : IAuditLogListService
    {
        private readonly IFlowAuditLogCollect _AuditLog;
        private readonly IFlowAuditItemLogCollect _ItemLog;
        private readonly IEmpService _Emp;
        private readonly IFlowNodeService _Flow;
        private readonly IFlowAuditSignLogCollect _SignLog;
        private readonly IFlowAuditNodeStateCollect _NodeState;
        private readonly IFileService _File;
        public AuditLogListService ( IFlowAuditLogCollect auditLog,
            IFlowAuditItemLogCollect itemLog,
            IFlowAuditNodeStateCollect nodeState,
            IEmpService emp,
            IFileService file,
            IFlowAuditSignLogCollect siginLog,
            IFlowNodeService flow )
        {
            this._SignLog = siginLog;
            this._NodeState = nodeState;
            this._File = file;
            this._AuditLog = auditLog;
            this._ItemLog = itemLog;
            this._Emp = emp;
            this._Flow = flow;
        }
        private AuditLogItemDto[] _Items;
        private AuditLogItemDto[] _MarkItems;
        private EmpUnitDept[] _Emps;
        private AuditFlowBody _FlowBody;
        private UserFileData[] _Files;
        private AuditNodeState[] _State;
        public FlowAuditLog Get ( long logId )
        {
            AuditLogTemp log = this._AuditLog.Get<AuditLogTemp>(logId);
            this._FlowBody = this._Flow.Get(log.FlowId);
            long[] nodeId = this._FlowBody.Nodes.Values.Where(a => a.AuditType == FlowAuditType.多人会审 || a.NodeType == FlowNodeType.循环处理节点).Select(a => a.Id).ToArray();
            this._State = this._NodeState.GetNodeStatus(logId, nodeId);
            AuditLogItemDto[] items = this._ItemLog.GetsByLogId<AuditLogItemDto>(logId);
            this._Emps = this._Emp.GetsUnitDept(items.ConvertAll(a => a.EmpId));
            this._MarkItems = items.FindAll(a => ConstDic.MarkeStatus.Contains(a.MarkState));
            this._Items = items.FindAll(a => !ConstDic.MarkeStatus.Contains(a.MarkState));
            _NodeGroup[] begins = this._Items.Where(a => a.Status != FlowAuditItemStatus.已撤回 && ( ( a.RootNodeId == this._FlowBody.BeginNode && a.PrtBatchNo.HasValue == false && a.NodeType != FlowNodeType.子流程 ) || a.NodeType == FlowNodeType.子流程 )).GroupBy(a => new _NodeGroup
            {
                NodeId = a.NodeId,
                BatchNo = a.BatchNo
            }).Select(a => a.Key).ToArray();
            if ( this._FlowBody.Nodes.IsExists(a => a.Value.IsSign || a.Value.IsUpFile) )
            {
                List<long> itemId = new List<long>();
                items.ForEach<AuditLogItemDto>(a =>
                {
                    FlowNode node = this._FlowBody.Nodes[a.NodeId];
                    if ( node.IsSign || node.IsUpFile )
                    {
                        itemId.Add(a.Id);
                    }
                });
                this._Files = this._File.GetUserFiles(new string[] { "FlowAuditFile", "FlowAuditSign" }, itemId);
            }
            FlowAuditLog data = new FlowAuditLog
            {
                AuditStatus = log.AuditStatus,
                CreateTime = log.CreateTime,
                DocTitle = log.DocTitle,
                FlowId = log.FlowId,
                LinkPk = log.LinkPk,
                LinkType = log.LinkType,
                Id = log.Id,
                Items = begins.Select(a =>
                {
                    FlowNode node = this._FlowBody.Nodes[a.NodeId];
                    return this._Format(node, a.BatchNo);
                }).OrderBy(a => a.CreateTime).ToArray()
            };
            return data;
        }
        private AuditLogItem _FormatItem ( AuditLogItemDto item, FlowNode node )
        {
            AuditLogItem log = new AuditLogItem
            {
                Id = item.Id,
                Status = item.Status,
                SubFlowState = item.SubFlowState,
                AuditState = item.AuditState,
                MarkState = item.MarkState,
                AuditOpinion = item.AuditOpinion,
                StartTime = item.StartTime,
                AuditType = node.AuditType,
                EndTime = item.EndTime,
                Emp = this._Emps.Find(c => c.EmpId == item.EmpId),
                BatchNo = item.BatchNo,
                CreateTime = item.CreateTime,
                NodeId = item.NodeId,
                NodeName = node.NodeName,
                NodeType = node.NodeType,
                Show = node.AuditEmp?.Show,
                IsSign = node.IsSign,
                IsUpFile = node.IsUpFile,
                FormId = item.FormId
            };
            if ( this._Files != null )
            {
                if ( node.IsSign )
                {
                    log.SignFile = this._Files.Find(a => a.LinkBizPk == item.Id && a.DirKey == "FlowAuditSign", a => new AuditFile
                    {
                        FileId = a.FileId,
                        FileName = a.FileName,
                        FileUri = a.FileUri
                    });
                }
                if ( node.IsUpFile )
                {
                    log.Files = this._Files.Convert<UserFileData, AuditFile>(a => a.LinkBizPk == item.Id && a.DirKey == "FlowAuditFile", a => new AuditFile
                    {
                        FileId = a.FileId,
                        FileName = a.FileName,
                        FileUri = a.FileUri
                    });
                }
                if ( node.IsUpFileSign )
                {
                    log.PdfSignFile = this._Files.Convert<UserFileData, AuditFile>(a => a.LinkBizPk == item.Id && a.DirKey == "FlowAuditFile", a => new AuditFile
                    {
                        FileId = a.FileId,
                        FileName = a.FileName,
                        FileUri = a.FileUri
                    });
                }
            }
            return log;
        }
        private AuditLogItem _Format ( FlowNode node, long batchNo )
        {
            if ( node.NodeType == FlowNodeType.开始节点 || node.NodeType == FlowNodeType.结束节点 )
            {
                AuditLogItemDto item = this._Items.Find(c => c.NodeId == node.Id && c.BatchNo == batchNo);
                return this._FormatItem(item, node);
            }
            else if ( node.NodeType == FlowNodeType.子流程 )
            {
                return this._GetSubFlowLog(node, batchNo);
            }
            else if ( node.NodeType == FlowNodeType.循环处理节点 )
            {
                return this._GetWhileFlowLog(node, batchNo);
            }
            else if ( node.AuditType == FlowAuditType.多人会审 )
            {
                return this._MultipleAuditLog(node, batchNo);
            }
            else
            {
                AuditLogItemDto item = this._Items.Find(c => c.NodeId == node.Id && c.BatchNo == batchNo);
                if ( ConstDic.ReturnStatus.Contains(item.Status) )
                {
                    List<AuditLogItemDto> chil = [item];
                    this._LoadMark(item, chil);
                    return new AuditLogItem
                    {
                        AuditType = node.AuditType,
                        BatchNo = batchNo,
                        CreateTime = item.CreateTime,
                        NodeId = node.Id,
                        NodeName = node.NodeName,
                        NodeType = node.NodeType,
                        Status = item.Status,
                        Show = node.AuditEmp.Show,
                        Children = chil.OrderBy(a => a.CreateTime).Select(a => this._FormatItem(a, node)).ToArray()
                    };
                }
                return this._FormatItem(item, node);
            }
        }
        private AuditLogItem _GetWhileFlowLog ( FlowNode node, long batchNo )
        {
            AuditLogItemDto root = this._Items.Find(a => a.NodeId == node.Id && a.BatchNo == batchNo);
            AuditLogItemDto[] items = this._Items.FindAll(c => c.NodeId == node.Id && c.PrtBatchNo == batchNo).Insert(root, 0);
            FlowNodeAuditStatus status = this._State.Find(c => c.NodeId == node.Id, c => c.Status);
            AuditLogItem main = new AuditLogItem
            {
                AuditType = node.AuditType,
                BatchNo = batchNo,
                CreateTime = root.CreateTime,
                NodeId = node.Id,
                NodeName = node.NodeName,
                NodeType = node.NodeType,
                Status = FlowAuditItemStatus.审核进行中,
                Show = node.AuditEmp.Show
            };
            if ( status == FlowNodeAuditStatus.审核通过 )
            {
                main.Status = FlowAuditItemStatus.审核通过;
            }
            else if ( status == FlowNodeAuditStatus.审核未通过 )
            {
                main.Status = FlowAuditItemStatus.审核未通过;
            }
            else if ( status == FlowNodeAuditStatus.待开始 )
            {
                main.Status = FlowAuditItemStatus.已作废;
            }
            if ( items.IsExists(c => ConstDic.ReturnStatus.Contains(c.Status)) )
            {
                List<AuditLogItemDto> list = new List<AuditLogItemDto>();
                items.ForEach(c =>
                {
                    list.Add(c);
                    if ( ConstDic.ReturnStatus.Contains(c.Status) )
                    {
                        this._LoadMark(c, list);
                    }
                });
                main.Children = list.OrderBy(a => a.CreateTime).Select(a => this._FormatItem(a, node)).ToArray();
            }
            else
            {
                main.Children = items.ConvertAll(a => this._FormatItem(a, node));
            }
            return main;
        }
        private AuditLogItem _GetSubFlowLog ( FlowNode node, long batchNo )
        {
            AuditLogItemDto[] dtos = this._Items.Where(a => a.RootNodeId == node.Id && a.RootBatchNo == batchNo).OrderBy(a => a.CreateTime).ToArray();
            AuditLogItem main = new AuditLogItem
            {
                AuditType = node.AuditType,
                BatchNo = batchNo,
                CreateTime = dtos[0].CreateTime,
                NodeId = node.Id,
                NodeName = node.NodeName,
                NodeType = node.NodeType,
                Status = dtos[^1].Status
            };
            if ( dtos.IsExists(c => ConstDic.ReturnStatus.Contains(c.Status)) )
            {
                List<AuditLogItemDto> list = new List<AuditLogItemDto>();
                dtos.ForEach(c =>
                {
                    list.Add(c);
                    if ( ConstDic.ReturnStatus.Contains(c.Status) )
                    {
                        this._LoadMark(c, list);
                    }
                });
                main.Children = list.OrderBy(a => a.CreateTime).Select(a => this._FormatItem(a, this._FlowBody.Nodes[a.NodeId])).ToArray();
            }
            else
            {
                main.Children = dtos.ConvertAll(a => this._FormatItem(a, this._FlowBody.Nodes[a.NodeId]));
            }
            return main;
        }
        private AuditLogItem _MultipleAuditLog ( FlowNode node, long batchNo )
        {
            AuditLogItemDto[] dtos = this._Items.Where(a => a.NodeId == node.Id && a.BatchNo == batchNo).OrderBy(a => a.CreateTime).ToArray();
            AuditLogItem main = new AuditLogItem
            {
                AuditType = node.AuditType,
                BatchNo = batchNo,
                CreateTime = dtos[0].CreateTime,
                NodeId = node.Id,
                NodeName = node.NodeName,
                NodeType = node.NodeType,
                Status = FlowAuditItemStatus.审核进行中,
                Show = node.AuditEmp.Show
            };
            FlowNodeAuditStatus status = this._State.Find(c => c.NodeId == node.Id, c => c.Status);
            if ( status == FlowNodeAuditStatus.审核通过 )
            {
                main.Status = FlowAuditItemStatus.审核通过;
            }
            else if ( status == FlowNodeAuditStatus.审核未通过 )
            {
                main.Status = FlowAuditItemStatus.审核未通过;
            }
            else if ( status == FlowNodeAuditStatus.待开始 )
            {
                main.Status = FlowAuditItemStatus.已作废;
            }
            if ( dtos.IsExists(c => ConstDic.ReturnStatus.Contains(c.Status)) )
            {
                List<AuditLogItemDto> list = new List<AuditLogItemDto>();
                dtos.ForEach(c =>
                {
                    list.Add(c);
                    if ( ConstDic.ReturnStatus.Contains(c.Status) )
                    {
                        this._LoadMark(c, list);
                    }
                });
                main.Children = list.OrderBy(a => a.CreateTime).Select(a => this._FormatItem(a, node)).ToArray();
            }
            else
            {
                main.Children = dtos.ConvertAll(a => this._FormatItem(a, node));
            }
            return main;
        }
        private void _LoadMark ( AuditLogItemDto item, List<AuditLogItemDto> list )
        {
            if ( item.Status == FlowAuditItemStatus.已委托 )
            {
                AuditLogItemDto t = this._MarkItems.Find(a => a.OptItemId == item.Id && a.MarkState == FlowItemMarkState.回源);
                if ( t != null )
                {
                    list.Add(t);
                    if ( ConstDic.ReturnStatus.Contains(t.Status) )
                    {
                        this._LoadMark(t, list);
                    }
                }
            }
            AuditLogItemDto dto = this._MarkItems.Find(a => a.OptItemId == item.Id && a.MarkState != FlowItemMarkState.回源);
            if ( dto != null )
            {
                list.Add(dto);
                if ( ConstDic.ReturnStatus.Contains(dto.Status) || ConstDic.MarkeStatus.Contains(dto.MarkState) )
                {
                    this._LoadMark(dto, list);
                }
            }
        }

        public long[] GetLogItemIds ( long logId )
        {
            throw new NotImplementedException();
        }

        private class _NodeGroup
        {
            public long NodeId { get; set; }

            public long BatchNo { get; set; }

            public override bool Equals ( object? obj )
            {
                if ( obj is _NodeGroup i )
                {
                    return i.NodeId == this.NodeId && this.BatchNo == this.BatchNo;
                }
                return false;
            }
            public override int GetHashCode ()
            {
                return ( this.NodeId + "_" + this.BatchNo ).GetHashCode();
            }
        }
    }
}
